package com.iiordanov.android.drawing;

import com.iiordanov.util.ObjectPool;
import com.iiordanov.util.SafeObjectPool;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;

public class OverlappingCopy
{
    private static SafeObjectPool<Rect> ocRectPool = new SafeObjectPool<Rect>() {
        @Override
        protected Rect itemForPool()
        {
            return new Rect();
        }
    };
    private static void transformRect(Rect source, Rect transformedSource, int deltaX, int deltaY)
    {
        transformedSource.set(deltaX < 0 ? source.right * -1 : source.left,
                deltaY < 0 ? source.bottom * -1 : source.top,
                deltaX < 0 ? source.left * -1 : source.right,
                deltaY < 0 ? source.top * -1 : source.bottom);        
    }
    private static void copyTransformedRect(Rect stepSourceRect, Rect stepDestRect, int deltaX, int deltaY, Bitmap data, Canvas bitmapBackedCanvas, Paint paint)
    {
        transformRect(stepSourceRect,stepSourceRect,deltaX,deltaY);
        stepDestRect.set(stepSourceRect);
        stepDestRect.offset(deltaX,deltaY);
        bitmapBackedCanvas.drawBitmap(data, stepSourceRect, stepDestRect, paint);
    }
    public static void Copy(Bitmap data, Canvas bitmapBackedCanvas, Paint paint, Rect source, int destX, int destY)
    {
        Copy(data,bitmapBackedCanvas,paint,source,destX,destY,ocRectPool);
    }
    public static void Copy(Bitmap data, Canvas bitmapBackedCanvas, Paint paint, Rect source, int destX, int destY, ObjectPool<Rect> rectPool)
    {
        //android.util.Log.i("LBM","Copy "+source.toString()+" to "+destX+","+destY);
        int deltaX = destX - source.left;
        int deltaY = destY - source.top;
        int absDeltaX = deltaX < 0 ? -deltaX : deltaX;
        int absDeltaY = deltaY < 0 ? -deltaY : deltaY;
        
        // Look for degenerate case
        if (absDeltaX == 0 && absDeltaY == 0)
            return;
        // Look for non-overlap case
        if (absDeltaX >= source.right - source.left || absDeltaY >= source.bottom - source.top)
        {
            // Non-overlapping copy
            ObjectPool.Entry<Rect> entry = rectPool.reserve();
            Rect dest = entry.get();
            dest.set(source.left + deltaX, source.top + deltaY, source.right + deltaX, source.bottom + deltaY);
            bitmapBackedCanvas.drawBitmap(data, source, dest, paint);
            rectPool.release(entry);
            return;
        }
        // Determine coordinate transform so that dest rectangle is always down and to the right.
        ObjectPool.Entry<Rect> transformedSourceEntry = rectPool.reserve();
        Rect transformedSource = transformedSourceEntry.get();
        transformRect(source,transformedSource,deltaX,deltaY);
        ObjectPool.Entry<Rect> transformedDestEntry = rectPool.reserve();
        Rect transformedDest = transformedDestEntry.get();
        transformedDest.set(transformedSource);
        transformedDest.offset(absDeltaX, absDeltaY);
        ObjectPool.Entry<Rect> intersectEntry = rectPool.reserve();
        Rect intersect = intersectEntry.get();
        intersect.setIntersect(transformedSource, transformedDest);
        
        boolean xStepDone = false;
        int xStepWidth;
        int yStepHeight;
        if (absDeltaX > absDeltaY)
        {
            xStepWidth = absDeltaX;
            yStepHeight = source.bottom - source.top - absDeltaY;
        }
        else
        {
            xStepWidth = source.right - source.left - absDeltaX;
            yStepHeight = absDeltaY;
        }
        
        ObjectPool.Entry<Rect> stepSourceEntry = rectPool.reserve();
        Rect stepSourceRect = stepSourceEntry.get();
        ObjectPool.Entry<Rect> stepDestEntry = rectPool.reserve();
        Rect stepDestRect = stepDestEntry.get();
        
        for (int xStep = 0; ! xStepDone; xStep++)
        {
            int stepRight = intersect.right - xStep * xStepWidth;
            int stepLeft = stepRight - xStepWidth;
            if (stepLeft <= intersect.left)
            {
                stepLeft = intersect.left;
                xStepDone = true;
            }
            boolean yStepDone = false;
            for (int yStep = 0; ! yStepDone; yStep++)
            {
                int stepBottom = intersect.bottom - yStep * yStepHeight;
                int stepTop = stepBottom - yStepHeight;
                if (stepTop <= intersect.top)
                {
                    stepTop = intersect.top;
                    yStepDone = true;
                }
                stepSourceRect.set(stepLeft,stepTop,stepRight,stepBottom);
                //android.util.Log.i("LBM","Copy transformed "+stepSourceRect.toString()+" "+deltaX+" "+deltaY);
                copyTransformedRect(stepSourceRect, stepDestRect, deltaX, deltaY, data, bitmapBackedCanvas, paint);
            }
        }
        if (absDeltaX>0)
        {
            // Copy left edge
            stepSourceRect.set(transformedSource.left,transformedSource.top,intersect.left,transformedSource.bottom);
            copyTransformedRect(stepSourceRect, stepDestRect, deltaX, deltaY, data, bitmapBackedCanvas, paint);
        }
        if (absDeltaY>0)
        {
            // Copy top excluding left edge
            stepSourceRect.set(intersect.left,transformedSource.top,transformedSource.right,intersect.top);
            copyTransformedRect(stepSourceRect, stepDestRect, deltaX, deltaY, data, bitmapBackedCanvas, paint);
        }
        
        rectPool.release(stepDestEntry);
        rectPool.release(stepSourceEntry);
        rectPool.release(intersectEntry);
        rectPool.release(transformedDestEntry);
        rectPool.release(transformedSourceEntry);
    }
}


